package com.itHuangTao.tank;

import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.dsl.components.*;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.EntityFactory;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.Spawns;
import com.almasb.fxgl.entity.components.CollidableComponent;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.texture.AnimatedTexture;
import com.almasb.fxgl.texture.AnimationChannel;
import com.almasb.fxgl.ui.ProgressBar;
import com.itHuangTao.tank.components.*;
import javafx.geometry.Point2D;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

import java.util.Locale;

//创建实体工厂类
public class TankEntityFactory implements EntityFactory {

    public static AnimatedTexture at;

    @Spawns("player")
    public Entity newPlayer(SpawnData data) {
        //给我方坦克加一个生命值组件
        HealthIntComponent hpComponent = new HealthIntComponent(Config.MAX_HP);
        hpComponent.setValue(Config.MAX_HP);
        //利用进度条来表示生命值(false是关闭动画的血条演变效果)
        ProgressBar hpBar = new ProgressBar(false);
        //关闭显示扣除血条文字
        hpBar.setLabelVisible(false);
        //设置血条样式
        hpBar.setWidth(39);
        hpBar.setHeight(8);
        hpBar.setTranslateY(42);
        hpBar.setFill(Color.LIGHTGREEN);
        //血量不同显示的血条颜色不同(ob是观测对象，ov是之前的值，nv是当前的值)
        hpBar.currentValueProperty().addListener((ob, ov, nv) -> {
            if (nv.intValue() <= Config.MAX_HP * 0.4) {
                hpBar.setFill(Color.RED);
            } else if (nv.intValue() <= Config.MAX_HP * 0.8) {
                hpBar.setFill(Color.YELLOW);
            } else {
                hpBar.setFill(Color.LIGHTGREEN);
            }
        });

        hpBar.setMaxValue(Config.MAX_HP);//最大生命值
        hpBar.currentValueProperty().bind(hpComponent.valueProperty());//绑定当前生命值
        //创建并返回一个玩家坦克实体
        return FXGL.entityBuilder(data)
                .type(GameType.PLAYER)              //枚举类(表示玩家)
                .viewWithBBox("tank/H1U.png")   //和原图大小一样的构建大小和外观
                .view(hpBar)                             //玩家生命值
                .with(new EffectComponent())            //添加效果组件
                .with(new TankComponent())               //坦克组件(创建一个坦克实体)
                .with(hpComponent)                      //我方坦克生命值组件
                .with(new TankLevelComponent())         //坦克等级
                .with(new CollidableComponent(true))    //碰撞
                .build();
    }

    @Spawns("enemy")
    public Entity newEnemy(SpawnData data) {
        Image image = FXGL.image("tank/spawnTank.png");
        AnimationChannel ac = new AnimationChannel(
                image, Duration.seconds(0.5), 4);
        at = new AnimatedTexture(ac);
        //创建并返回一个敌人坦克实体
        return FXGL.entityBuilder(data)
                .type(GameType.ENEMY)              //枚举类(表示敌方坦克)
                .with(new EffectComponent())            //添加效果组件
                .with(new TankComponent())              //坦克组件(创建一个坦克实体)
                .with(new TankLevelComponent())     //坦克等级
                .viewWithBBox(at.loop())   //播放敌人坦克出现的效果
                .with(new EnemyComponent())       //自定义一个控制敌人坦克行为的组件
                .with(new CollidableComponent(true))    //碰撞
                .build();
    }

    @Spawns("brick")
    public Entity newBrick(SpawnData data) {
        //创建并返回一个砖块实体
        return FXGL.entityBuilder(data)
                .type(GameType.BRICK)
                .bbox(BoundingShape.box(
                        Config.CELL_SIZE, Config.CELL_SIZE
                ))               //一个格子图片的大小
                .collidable()   //碰撞
                .neverUpdated() //拒绝更新图片
                .build();
    }

    @Spawns("greens")
    public Entity newGreens(SpawnData data) {
        //创建并返回一个森林实体
        return FXGL.entityBuilder(data)
                .type(GameType.GREENS)
                .bbox(BoundingShape.box(Config.CELL_SIZE, Config.CELL_SIZE))
                .collidable()   //碰撞
                .zIndex(1000)   //提高这个图片的层级（使其在和其它图片碰撞时显现在上面）
                .neverUpdated() //拒绝更新图片
                .build();

    }

    @Spawns("sea")
    public Entity newSea(SpawnData data) {
        //创建一个动态纹理(每1秒刷新一帧，这张图片有两帧)
        AnimationChannel ac = new AnimationChannel(
                FXGL.image("map/sea_anim.png"), Duration.seconds(1), 2);
        AnimatedTexture at = new AnimatedTexture(ac);

        //创建并返回一个水面实体
        return FXGL.entityBuilder(data)
                .type(GameType.SEA)
                .viewWithBBox(at.loop())//循环播放水面的图片帧
                .collidable()   //碰撞
                .build();
    }

    @Spawns("border")
    public Entity newBorder(SpawnData data) {
        //创建并返回一个边界实体
        int width = data.<Integer>get("width");
        int height = data.<Integer>get("height");
        return FXGL.entityBuilder(data)
                .type(GameType.BORDER)
                .viewWithBBox(new Rectangle(width, height, Color.LIGHTGRAY))
                .collidable()       //碰撞
                .neverUpdated()     //拒绝更新图片
                .build();
    }

    @Spawns("snow")
    public Entity newSnow(SpawnData data) {
        //创建并返回一个雪花实体
        return FXGL.entityBuilder(data)
                .type(GameType.SNOW)
                .bbox(BoundingShape.box(
                        Config.CELL_SIZE, Config.CELL_SIZE
                ))
                .collidable()   //碰撞
                .neverUpdated() //拒绝更新图片
                .build();
    }

    @Spawns("stone")
    public Entity newStone(SpawnData data) {
        //创建并返回一个石头实体
        return FXGL.entityBuilder(data)
                .type(GameType.STONE)
                .bbox(BoundingShape.box(
                        Config.CELL_SIZE, Config.CELL_SIZE
                ))
                .collidable()   //碰撞
                .neverUpdated() //拒绝更新图片
                .build();
    }

    @Spawns("bullet")
    public Entity newBullet(SpawnData data) {
        //播放子弹发射音效
        FXGL.play("normalFire.wav");
        Point2D dir = data.get("dir");

        //完成敌我子弹碰撞识别系统
        //默认碰撞正常
        CollidableComponent collidableComponent = new CollidableComponent(true);
        //碰撞条件改正为同类被忽略碰撞
        collidableComponent.addIgnoredType(data.<GameType>get("ownerType"));

        return FXGL.entityBuilder(data)
                .type(GameType.BULLET)
                .viewWithBBox("bullet/plus.png")
                .with(new ProjectileComponent(dir, Config.BULLET_SPEED))//API的内部类可以快速创建一个子弹的对象(参数为子弹的方向和速度)
                .with(collidableComponent)
                .build();
    }

    @Spawns("explode")
    public Entity newExplode(SpawnData data) {
        //播放爆炸音效
        FXGL.play("normalBomb.wav");
        //创建一个爆炸实体
        AnimationChannel ac = new AnimationChannel(FXGL.image("explode.png"),
                Config.EXPLODE_TIME,
                9);//播放间隔时间为每一帧0.35秒，有9帧
        AnimatedTexture at = new AnimatedTexture(ac);
        return FXGL.entityBuilder(data)
                .view(at.play())//播放一次
                .with(new ExpireCleanComponent(Config.EXPLODE_TIME))//过期清理组件：时间一过，把游戏实体从游戏世界中移除
                .build();
    }

    @Spawns("item")
    public Entity newItem(SpawnData data) {
        //随机获取枚举类里面的道具类型
        ItemType itemType = FXGLMath.random(ItemType.values()).get();

        //改变第四，第六和第七关出现道具的概率的方法（船出现的概率会更高）
        itemType = getItemType(itemType);
        //导入道具类型
        data.put("itemType", itemType);
        return FXGL.entityBuilder(data)
                .type(GameType.ITEM)
                .viewWithBBox("item/" + itemType.toString().toLowerCase(Locale.ROOT) + ".png")//准确定位道具的类型
                .collidable()   //碰撞
                .zIndex(2000)
                .build();
    }

    @Spawns("flag")
    public Entity newFlag(SpawnData data) {
        return FXGL.entityBuilder(data)
                .type(GameType.FLAG)
                .bbox(BoundingShape.box(48, 48))
                .with(new FlagComponent())
                .collidable()
                .build();
    }

    //改变道具出现的概率
    private static ItemType getItemType(ItemType itemType) {
        //岛屿奇兵和决战威尼斯
        if (FXGL.geti("level") == 4 || FXGL.geti("level") == 8) {
            if (FXGLMath.randomBoolean(0.5)) {
                return ItemType.SHIP;
            }
        }
        //石门庄和护城战争
        if (FXGL.geti("level") == 7 || FXGL.geti("level") == 6) {
            if (FXGLMath.randomBoolean(0.2)) {
                return ItemType.SHIP;
            }
        }
        //对炸弹的处理
        if (FXGL.geti("level") <= 4 && itemType == ItemType.BOMB) {
            //基础关卡（有1个炸弹）
            if (FXGLMath.randomBoolean(0.9) && TankApp.BombCountMax > 1) {
                //是炸弹的情况下再重新刷新一次选择
                itemType = FXGLMath.random(ItemType.values()).get();
                //还是炸弹就出现
                if (itemType == ItemType.BOMB) {
                    TankApp.BombCountMax--;
                    return ItemType.BOMB;
                }
            } else if (TankApp.BombCountMax == 0) {
                //达到炸弹的上限就出现tank回血
                return ItemType.TANK;
            }
        } else if (FXGL.geti("level") >= 5 && itemType == ItemType.BOMB) {
            //关卡增强(有三个炸弹)
            if (FXGLMath.randomBoolean(0.8) && TankApp.BombCountMax > -1) {
                //是炸弹的情况下再重新刷新一次选择
                itemType = FXGLMath.random(ItemType.values()).get();
                //还是炸弹就出现
                if (itemType == ItemType.BOMB) {
                    TankApp.BombCountMax--;
                    return ItemType.BOMB;
                }
            } else if (TankApp.BombCountMax == -1) {
                //达到炸弹的上限就出现坦克
                return ItemType.TANK;
            }
        }
        //对枪炮的处理
        if (FXGL.geti("level") == 3
                || FXGL.geti("level") == 5
                || FXGL.geti("level") == 7) {
            if (itemType == ItemType.GUN) {
                return ItemType.TANK;
            }
        } else if (itemType == ItemType.GUN) {
            if (FXGLMath.randomBoolean(0.8)) {
                return ItemType.TANK;
            }
        }
        return itemType;
    }
}
